// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//==========================================================================
//  File:       ByteBufferPool.cs 
// 
//  Summary:    Stream used for reading from a socket by remoting channels.
// 
//=========================================================================

using System;
using System.Threading; 

 
namespace System.IO 
{
 
    internal interface IByteBufferPool
    {
        byte[] GetBuffer();
        void ReturnBuffer(byte[] buffer); 
    }
 
 
    // This isn't actually a buffer pool. It always creates a new byte buffer.
    internal class ByteBufferAllocator : IByteBufferPool 
    {
        private int _bufferSize;

        public ByteBufferAllocator(int bufferSize) 
        {
            _bufferSize = bufferSize; 
        } 

        public byte[] GetBuffer() 
        {
            return new byte[_bufferSize];
        }
 
        public void ReturnBuffer(byte[] buffer)
        { 
        } 

    } // ByteBufferAllocator 


    internal class ByteBufferPool : IByteBufferPool
    { 
        private byte[][] _bufferPool = null;
 
        private int _current; // -1 for none 
        private int _last;
        private int _max;     // maximum number of buffers to pool 

        private int _bufferSize;

        private Object _controlCookie = "cookie object"; 

 
        public ByteBufferPool(int maxBuffers, int bufferSize) 
        {
            _max = maxBuffers; 
            _bufferPool = new byte[_max][];
            _bufferSize = bufferSize;

            _current = -1; 
            _last = -1;
        } // ByteBufferPool 
 

        public byte[] GetBuffer() 
        {
            Object cookie = null;

            try 
            {
                // If a ThreadAbortException gets thrown after the exchange, 
                //   but before the result is assigned to cookie, then the 
                //   control cookie is lost forever. However, the buffer pool
                //   will still function normally and return everybody a new 
                //   buffer each time (that isn't very likely to happen,
                //   so we don't really care).
                cookie = Interlocked.Exchange(ref _controlCookie, null);
 
                if (cookie != null)
                { 
                    // we have the control cookie, so take a buffer 

                    if (_current == -1) 
                    {
                        _controlCookie = cookie;
                        // no pooled buffers available
                        return new byte[_bufferSize]; 
                    }
                    else 
                    { 
                        // grab next available buffer
                        byte[] buffer = _bufferPool[_current]; 
                        _bufferPool[_current] = null;

                        // update "current" index
                        if (_current == _last) 
                        {
                            // this is the last free buffer 
                            _current = -1; 
                        }
                        else 
                        {
                            _current = (_current + 1) % _max;
                        }
 
                        _controlCookie = cookie;
                        return buffer; 
                    } 
                }
                else 
                {
                    // we don't have the control cookie, so just create a new buffer since
                    //   there will probably be a lot of contention anyway.
                    return new byte[_bufferSize]; 
                }
            } 
            catch (ThreadAbortException) 
            {
                if (cookie != null) 
                {
                    // This should be rare, so just reset
                    //   everything to the initial state.
                    _current = -1; 
                    _last = -1;
 
                    // restore cookie 
                    _controlCookie = cookie;
                } 

                throw;
            }
        } // GetBuffer 

 
        public void ReturnBuffer(byte[] buffer) 
        {
            if (buffer == null) 
                throw new ArgumentNullException("buffer");


            // The purpose of the buffer pool is to try to reduce the 
            //   amount of garbage generated, so it doesn't matter  if
            //   the buffer gets tossed out. Since we don't want to 
            //   take the perf hit of taking a lock, we only return 
            //   the buffer if we can grab the control cookie.
 
            Object cookie = null;

            try
            { 
                // If a ThreadAbortException gets thrown after the exchange,
                //   but before the result is assigned to cookie, then the 
                //   control cookie is lost forever. However, the buffer pool 
                //   will still function normally and return everybody a new
                //   buffer each time (that isn't very likely to happen, 
                //   so we don't really care).
                cookie = Interlocked.Exchange(ref _controlCookie, null);

                if (cookie != null) 
                {
                    if (_current == -1) 
                    { 
                        _bufferPool[0] = buffer;
                        _current = 0; 
                        _last = 0;
                    }
                    else
                    { 
                        int newLast = (_last + 1) % _max;
                        if (newLast != _current) 
                        { 
                            // the pool isn't full so store this buffer
                            _last = newLast; 
                            _bufferPool[_last] = buffer;
                        }
                    }
 
                    _controlCookie = cookie;
                } 
            } 
            catch (ThreadAbortException)
            { 
                if (cookie != null)
                {
                    // This should be rare, so just reset
                    //   everything to the initial state. 
                    _current = -1;
                    _last = -1; 
 
                    // restore cookie
                    _controlCookie = cookie; 
                }

                throw;
            } 
        } // ReturnBuffer
 
 

    } // ByteBufferPool 


} // namespace System.IO

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
//==========================================================================
//  File:       ByteBufferPool.cs 
// 
//  Summary:    Stream used for reading from a socket by remoting channels.
// 
//=========================================================================

using System;
using System.Threading; 

 
namespace System.IO 
{
 
    internal interface IByteBufferPool
    {
        byte[] GetBuffer();
        void ReturnBuffer(byte[] buffer); 
    }
 
 
    // This isn't actually a buffer pool. It always creates a new byte buffer.
    internal class ByteBufferAllocator : IByteBufferPool 
    {
        private int _bufferSize;

        public ByteBufferAllocator(int bufferSize) 
        {
            _bufferSize = bufferSize; 
        } 

        public byte[] GetBuffer() 
        {
            return new byte[_bufferSize];
        }
 
        public void ReturnBuffer(byte[] buffer)
        { 
        } 

    } // ByteBufferAllocator 


    internal class ByteBufferPool : IByteBufferPool
    { 
        private byte[][] _bufferPool = null;
 
        private int _current; // -1 for none 
        private int _last;
        private int _max;     // maximum number of buffers to pool 

        private int _bufferSize;

        private Object _controlCookie = "cookie object"; 

 
        public ByteBufferPool(int maxBuffers, int bufferSize) 
        {
            _max = maxBuffers; 
            _bufferPool = new byte[_max][];
            _bufferSize = bufferSize;

            _current = -1; 
            _last = -1;
        } // ByteBufferPool 
 

        public byte[] GetBuffer() 
        {
            Object cookie = null;

            try 
            {
                // If a ThreadAbortException gets thrown after the exchange, 
                //   but before the result is assigned to cookie, then the 
                //   control cookie is lost forever. However, the buffer pool
                //   will still function normally and return everybody a new 
                //   buffer each time (that isn't very likely to happen,
                //   so we don't really care).
                cookie = Interlocked.Exchange(ref _controlCookie, null);
 
                if (cookie != null)
                { 
                    // we have the control cookie, so take a buffer 

                    if (_current == -1) 
                    {
                        _controlCookie = cookie;
                        // no pooled buffers available
                        return new byte[_bufferSize]; 
                    }
                    else 
                    { 
                        // grab next available buffer
                        byte[] buffer = _bufferPool[_current]; 
                        _bufferPool[_current] = null;

                        // update "current" index
                        if (_current == _last) 
                        {
                            // this is the last free buffer 
                            _current = -1; 
                        }
                        else 
                        {
                            _current = (_current + 1) % _max;
                        }
 
                        _controlCookie = cookie;
                        return buffer; 
                    } 
                }
                else 
                {
                    // we don't have the control cookie, so just create a new buffer since
                    //   there will probably be a lot of contention anyway.
                    return new byte[_bufferSize]; 
                }
            } 
            catch (ThreadAbortException) 
            {
                if (cookie != null) 
                {
                    // This should be rare, so just reset
                    //   everything to the initial state.
                    _current = -1; 
                    _last = -1;
 
                    // restore cookie 
                    _controlCookie = cookie;
                } 

                throw;
            }
        } // GetBuffer 

 
        public void ReturnBuffer(byte[] buffer) 
        {
            if (buffer == null) 
                throw new ArgumentNullException("buffer");


            // The purpose of the buffer pool is to try to reduce the 
            //   amount of garbage generated, so it doesn't matter  if
            //   the buffer gets tossed out. Since we don't want to 
            //   take the perf hit of taking a lock, we only return 
            //   the buffer if we can grab the control cookie.
 
            Object cookie = null;

            try
            { 
                // If a ThreadAbortException gets thrown after the exchange,
                //   but before the result is assigned to cookie, then the 
                //   control cookie is lost forever. However, the buffer pool 
                //   will still function normally and return everybody a new
                //   buffer each time (that isn't very likely to happen, 
                //   so we don't really care).
                cookie = Interlocked.Exchange(ref _controlCookie, null);

                if (cookie != null) 
                {
                    if (_current == -1) 
                    { 
                        _bufferPool[0] = buffer;
                        _current = 0; 
                        _last = 0;
                    }
                    else
                    { 
                        int newLast = (_last + 1) % _max;
                        if (newLast != _current) 
                        { 
                            // the pool isn't full so store this buffer
                            _last = newLast; 
                            _bufferPool[_last] = buffer;
                        }
                    }
 
                    _controlCookie = cookie;
                } 
            } 
            catch (ThreadAbortException)
            { 
                if (cookie != null)
                {
                    // This should be rare, so just reset
                    //   everything to the initial state. 
                    _current = -1;
                    _last = -1; 
 
                    // restore cookie
                    _controlCookie = cookie; 
                }

                throw;
            } 
        } // ReturnBuffer
 
 

    } // ByteBufferPool 


} // namespace System.IO

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
